#include <stdio.h>
#include <string.h>

static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static void encode_3byte(const unsigned char* src, char* dst)
{
    dst[0] = base64_table[src[0] >> 2];
    dst[1] = base64_table[((src[0] & 0x03) << 4) | (src[1] >> 4)];
    dst[2] = base64_table[((src[1] & 0x0f) << 2) | (src[2] >> 6)];
    dst[3] = base64_table[src[2] & 0x3f];
}

static void encode_2byte(const unsigned char* src, char* dst)
{
    dst[0] = base64_table[src[0] >> 2];
    dst[1] = base64_table[((src[0] & 0x03) << 4) | (src[1] >> 4)];
    dst[2] = base64_table[(src[1] & 0x0f) << 2];
    dst[3] = '=';
}

static void encode_1byte(const unsigned char* src, char* dst)
{
    dst[0] = base64_table[src[0] >> 2];
    dst[1] = base64_table[(src[0] & 0x03) << 4];
    dst[2] = dst[3] = '=';
}

size_t base64_encode(const unsigned char* src, size_t src_len, char* dst, size_t dst_len)
{
    size_t encode_len = 4 * ((src_len + 2) / 3);
    size_t left = src_len;

    if (!src || !dst) {
        return 0;
    }

    if (dst_len < encode_len) {
        return 0;
    }

    while (left >= 3) {
        encode_3byte(src, dst);
        left -= 3;
        src += 3;
        dst += 4;
    }

    switch (left) {
    case 1:
        encode_1byte(src, dst);
        left -= 1;
        src += 1;
        dst += 4;
        break;
    case 2:
        encode_2byte(src, dst);
        left -= 2;
        src += 2;
        dst += 4;
        break;
    }

    return encode_len;
}

int main()
{
    char buf[128];
    size_t buf_len = 128;
    size_t enclen;
    unsigned char s[] = {0xff, 0xff, 0xff};

    enclen = base64_encode(s, sizeof s, buf, buf_len);
    buf[enclen] = 0;
    puts(buf);
    return 0;
}
